#include "hashTable.h"
#include "logger.h"
#include <string.h>
Index Hash(const char *Key, int TableSize)
{
    unsigned int HashVal = 0;
    while (*Key != '\0')
        HashVal = (HashVal << 5) + *Key++;
    return HashVal % TableSize;
}

static int NextPrime(int N)
{
    int i;

    if (N % 2 == 0)
        N++;
    for (;; N += 2)
    {
        for (i = 3; i * i <= N; i += 2)
            if (N % i == 0)
                goto ContOuter; /* Sorry about this! */
        return N;
    ContOuter:;
    }
}

HashTable InitializeTable(int TableSize, EqualFunc Func)
{
    int i = 0;
    if (TableSize < MinTableSize)
        FatalError("Table size is too smalll");

    HashTable H = malloc(sizeof(*H));
    if (!H)
        FatalError("Out of space");
    H->TableSize = NextPrime(TableSize);
    H->TheLists = malloc(sizeof(*H->TheLists) * H->TableSize);
    H->Func = Func;

    if (!H->TheLists)
        FatalError("Out of space");
    for (i = 0; i < H->TableSize; i++)
    {
        H->TheLists[i] = malloc(sizeof(*H->TheLists[i]));
        if (!H->TheLists[i])
            FatalError("Out of space");
        H->TheLists[i]->Next = NULL;
    }
    goto _success;
_success:
    goto _exit;
_error:
    DestoryTable(H);
    H = NULL;
    goto _exit;
_exit:
    return H;
}

void DestoryTable(HashTable H)
{
    int i = 0;
    List TmpL = NULL;
    Position P = NULL;
    Position TmpP = NULL;

    if (H)
    {
        if (H->TheLists)
        {
            for (i = 0; i < H->TableSize; i++)
            {
                TmpL = H->TheLists[i];
                P = TmpL->Next;
                while (P)
                {
                    TmpP = P->Next;
                    if (P->Element)
                    {
                        free(P->Element);
                    }
                    free(P);
                    P = TmpP;
                }
            }
        }
        free(H->TheLists);
        free(H);
    }
}

Position Find(ElementType X, HashTable H)
{
    List L = NULL;
    Position P = NULL;
    L = H->TheLists[Hash(X, H->TableSize)];
    P = L->Next;
    while (P != NULL && H->Func(X, P->Element))
        P = P->Next;
    return P;
}

void Insert(ElementType X, HashTable H)
{
    Position P = NULL;
    List L = NULL;
    P = Find(X, H);
    if (!P)
    {
        P = malloc(sizeof(*P));
        if (!P)
            FatalError("Out of space");
        L = H->TheLists[Hash(X, H->TableSize)];
        P->Element = strdup(X);
        if (!P->Element)
            FatalError("Out of space");
        P->Next = L->Next;
        L->Next = P;
    }
}

void Print(HashTable H)
{
    int i = 0;
    List TmpL = NULL;
    Position P = NULL;
    for (i = 0; i < H->TableSize; i++)
    {
        TmpL = H->TheLists[i];
        P = TmpL->Next;
        while (P)
        {
            printf("key: %s\n", P->Element);
            P = P->Next;
        }
    }
}